package consensus

import (
	"fmt"
	"log"
	"ebbflow/pkg/cbr"
)

// EbbFlowCBR implements CBR protocol for EbbFlow
type EbbFlowCBR struct {
	integration *cbr.EbbFlowCBRIntegration
	logger      *log.Logger
}

// NewEbbFlowCBR creates a new EbbFlow CBR instance
func NewEbbFlowCBR(nodeID, totalNodes, faultyNodes int, logger *log.Logger) *EbbFlowCBR {
	return NewEbbFlowCBRWithInterval(nodeID, totalNodes, faultyNodes, 5, logger)
}

// NewEbbFlowCBRWithInterval creates a new EbbFlow CBR instance with custom reconfiguration interval
func NewEbbFlowCBRWithInterval(nodeID, totalNodes, faultyNodes, reconfigurationInterval int, logger *log.Logger) *EbbFlowCBR {
	if logger == nil {
		logger = log.Default()
	}
	
	// Create CBR integration configuration
	config := cbr.EbbFlowCBRConfig{
		NodeID:                  nodeID,
		TotalNodes:              totalNodes,
		FaultyNodes:             faultyNodes,
		ReconfigurationInterval: reconfigurationInterval,
		NetworkConfig: cbr.NetworkConfig{
			BaseIP:   "127.0.0.1",
			BasePort: 8000,
			IPList:   generateIPList(totalNodes),
			PortList: generatePortList(totalNodes, 8000),
		},
		EnableMetrics: true,
	}
	
	integration := cbr.NewEbbFlowCBRIntegration(config, logger)
	
	return &EbbFlowCBR{
		integration: integration,
		logger:      logger,
	}
}

// Execute executes the CBR protocol
func (c *EbbFlowCBR) Execute() error {
	return c.integration.Execute()
}

// ExecuteReconfiguration executes CBR reconfiguration for a specific epoch
func (c *EbbFlowCBR) ExecuteReconfiguration(epoch int, newMembership []string) (*cbr.CBRResult, error) {
	return c.integration.ExecuteReconfiguration(epoch, newMembership)
}

// ShouldExecute determines if CBR should be executed at the given epoch
func (c *EbbFlowCBR) ShouldExecute(epoch int) bool {
	return c.integration.ShouldExecuteCBR(epoch)
}

// GetMetrics returns CBR performance metrics
func (c *EbbFlowCBR) GetMetrics() *cbr.CBRMetrics {
	return c.integration.GetCBRMetrics()
}

// GetProofChain returns the proof chain
func (c *EbbFlowCBR) GetProofChain() *cbr.ProofChain {
	return c.integration.GetProofChain()
}

// GetProofEntry retrieves a proof entry by epoch
func (c *EbbFlowCBR) GetProofEntry(epoch int) *cbr.ProofEntry {
	return c.integration.GetProofEntry(epoch)
}

// Utility functions

func generateIPList(count int) []string {
	ips := make([]string, count)
	for i := 0; i < count; i++ {
		ips[i] = "127.0.0.1"
	}
	return ips
}

func generatePortList(count, basePort int) []string {
	ports := make([]string, count)
	for i := 0; i < count; i++ {
		ports[i] = fmt.Sprintf("%d", basePort+i)
	}
	return ports
}